【X68000(Z)アセンブラ講座 第012回 TEXTグラフィックス画面@】 2025/03/05   こんにちは!! 今回はTEXTグラフィックスの使い方を書いてみます。 「TEXTって表示できるのは文字だけじゃないの?」と思う方もいると思いますが 実はPC9801(16色機種)のCG画像VRAMと殆ど同じ仕組みです。 元ZOOMのプログラマーH君が 「ファランクスの敵弾はテキスト画面に描画しているので スプライトの節約になるし敵弾も無限のようにたくさん描画できる」と言ってました。 (僕はファランクスはとても素晴らしいと思いますし、 裏技も見付けてゲーム雑誌に採用された事もありますw) X680x0(Z)のTEXT画面サイズは1024x1024ピクセルですが、 CG画面の2バイト(16bit)毎に1色とは表示の仕組みが全く異なるので 以後TEXTグラフィックス画面の説明などを書いていきます。 破線の内側を'TextCG_1.s'と言うファイル名で保存して下さい。 ------------------------------------------------------------------------------------------------   ******************************************************************************** * * アプリ名 : TextCG_1.x * * TextCG表示のサンプル1 * * Ver1.00 * ******************************************************************************** * スプライトパレット0から15のうちパレット0はテキストパレットと共用。 * BGのパレットはスプライトと共用。 include A:\XC\INCLUDE\DOSCALL.MAC * OSコール用マクロの読み込み include A:\XC\INCLUDE\IOCSCALL.MAC * IOCS(BIOS)コール用マクロの読み込み * システム領域のアドレス cg_palette equ $E82000 * CG用パレットデータの先頭アドレス cg_buffer equ $C00000 * CG-VRAMの先頭アドレス cg_scroll_x equ $E80018 * CGスクロール X cg_scroll_y equ $E8001a * CGスクロール Y sp_palette equ $E82200 * スプライト用パレットデータの先頭アドレス sp_controll equ $EB0000 * スプライトスクロールレジスターの先頭アドレス sp_pattern equ $EB8000 * スプライトパターンデータの先頭アドレス pcg_area equ $EB8000 * SPRITEとBGのパターンデータの先頭アドレス bg_dataarea0 equ $EBC000 * BG画像0の先頭アドレス bg_dataarea1 equ $EBE000 * BG画像1の先頭アドレス bg_scroll_x0 equ $EB0800 * BG0のスクロールX座標 bg_scroll_y0 equ $EB0802 * BG1のスクロールY座標 bg_scroll_x1 equ $EB0804 * BG0のスクロールX座標 bg_scroll_y1 equ $EB0806 * BG1のスクロールY座標 text0 equ $E00000 * テキストVram プレーン0 text1 equ $E20000 * テキストVram プレーン1 text2 equ $E40000 * テキストVram プレーン2 text3 equ $E60000 * テキストVram プレーン3 vsync equ $E88001 * %00010000でV-Syncチェックする pad1 equ $E9A001 * ゲームパッド1 pad2 equ $E9A003 * ゲームパッド2 .cpu 68000 * CPUのタイプ .data * '.data'以降のデータはデータセクションに配置される sppal00: * GGGGG RRRRR BBBBB A * TEXT兼Spriteパレット dc.w %00000_00000_00000_0 dc.w %00000_00000_11111_0 dc.w %11111_00000_00000_0 dc.w %00000_11111_00000_0 dc.w %11111_00000_11111_0 dc.w %00000_11111_11111_0 dc.w %11111_11111_00000_0 dc.w %11111_11111_11111_0 dc.w %00111_00111_00111_0 dc.w %00000_00000_01111_0 dc.w %01111_00000_00000_0 dc.w %00000_01111_00000_0 dc.w %01111_00000_01111_0 dc.w %00000_01111_01111_0 dc.w %01111_01111_00000_0 dc.w %01111_01111_01111_0 .bss * '.bss'以降データバッファ .text * '.text'以降のプログラムはテキストセクションに配置される start: * スタートアドレス * カーソルをオフにする moveq.l #_OS_CUROF,d0 trap #15 * ランダム関数の初期化 move.l #23456,d0 * d0.lにランダムのシードを代入する dc.w $FE0D * ランダムのシードを設定する * ユーザーモードからスーパーバイザーモードに移行する moveq.l #_B_SUPER,d0 * d0にIOCS(BIOS)機能番号を代入 move.l #0,d1 * 数値0をd1に代入 movea.l d1,a1 * d1をa1にコピー trap #15 * IOCSコール実行 * 画面モードの設定 moveq.l #_CRTMOD,d0 * 画面モードの設定 move.w #10,d1 * 画面モードの番号 : 16 = 768x512x4bit / 10 = 256x256x8bit trap #15 * 画面をクリアして表示をオンにする moveq.l #_G_CLR_ON,d0 * 画面をクリアして表示をオンにする trap #15 * スプライト初期化 moveq.l #_SP_INIT,d0 trap #15 * スプライト表示をオンにする moveq.l #_SP_ON,d0 trap #15 bsr set_palette * スプライトパレット設定ルーチンの呼び出し bsr text_clear * TEXT-VRAMのクリアー loop: * メインループ開始 * V-Syncビットを監視してメインループを60fpsで動作させるタイミングを取る movea.l #vsync,a0 vsync_1: move.b (a0),d0 and.b #$10,d0 tst.b d0 beq vsync_1 vsync_2: move.b (a0),d0 and.b #$10,d0 tst.b d0 bne vsync_2 moveq.l #4,d0 * [1] bsr test_pset * [ESC]キーが押されたら終了処理'end:'にジャンプする moveq.l #_BITSNS,d0 moveq.l #0,d1 trap #15 and.b #%00000010,d0 tst.b d0 bne end bra loop * メインループの最初にジャンプする end: bsr text_clear moveq.l #_CRTMOD,d0 move.w #16,d1 trap #15 * カーソルをオンにする moveq.l #_OS_CURON,d0 trap #15 * スーパーバイザーモードからユーザーモードに戻る moveq.l #_B_SUPER,d0 move.l SP,a1 trap #15 * アプリ終了 dc.w _EXIT * OSコール実行 : _EXIT = プログラムの終了 * RGBQUAD { Blue8, Green8, Red8, Reserved8 } = %RRRRRRRR_GGGGGGGG_BBBBBBBB_AAAAAAAA * palette { Green5, Red5, Blue5, Alpha1 } = %GGGGG_RRRRR_BBBBB_A * Set Text(Sprite) Palette set_palette: movea.l #sp_palette,a0 * スプライト用パレットレジスターアドレス lea sppal00,a1 * パレットデータバッファアドレス moveq.l #0,d7 set_palette_1: move.w (a1)+,(a0)+ addq.w #1,d7 * 色番号を次の番号に更新する cmp.w #16,d7 * 現在の色番号と16を比較する blt set_palette_1 * 現在の色番号が16未満ならアドレスset_palette_1に飛ぶ rts * 呼出元に戻る * Clear TEXT-VRAM( 128KB * 4 ) text_clear: movea.l #text0,a0 moveq.l #0,d0 move.l #131072,d7 text_clear_1: move.l d0,(a0)+ subq.l #1,d7 bne text_clear_1 rts * テキスト画面の原点座標(0,0)にピクセルを置く test_pset: * in d0 = 4ビットカラー番号(0-15) move.w d0,d1 and.w #%00000001,d1 tst.w d1 beq test_pset_1 movea.l #text0,a0 move.b #%10000000,(a0) test_pset_1: move.w d0,d1 and.w #%00000010,d1 tst.w d1 beq test_pset_2 movea.l #text1,a0 move.b #%10000000,(a0) test_pset_2: move.w d0,d1 and.w #%00000100,d1 tst.w d1 beq test_pset_3 movea.l #text2,a0 move.b #%10000000,(a0) test_pset_3: and.w #%00001000,d0 tst.w d0 beq test_pset_4 movea.l #text3,a0 move.b #%10000000,(a0) test_pset_4: rts ------------------------------------------------------------------------------------------------ コマンドプロンプトから、 A>as TextCG_1.s [Enter] A>lk TextCG_1.o [Enter] A>TextCG_1.x [Enter] のように入力すると 左上原点座標(0,0)に色の付いたピクセルが表示されます。 コメントに'[1]'とある命令行で '4'以外の0-15の値に書き換えるとピクセルの色が変わります。 終了は[ESC]キーです。 [ TEXTグラフィックスの説明 ] TEXTグラフィックスの画面は「0か1だけの1ビットデータの集まり(1024x1024bit)のレイヤー」が 4枚重なって構成されています。 レイヤーが4枚なのでTEXT-VRAM上で任意の同一座標に0-15まで4ビットの任意の色番号を表現できます。 横1024ビットはデータ量128バイトと言う事になります。 128バイト×1024ラインで1レイヤーあたり128KBのVRAMが搭載されています。 例えば座標(0,0)に色番号5(%0101)を1ピクセル表示させる場合、 move.b #%10000000,$E00000 * レイヤー0にデータを書き込む move.b #%00000000,$E20000 * レイヤー1にデータを書き込む move.b #%10000000,$E40000 * レイヤー2にデータを書き込む move.b #%00000000,$E60000 * レイヤー3にデータを書き込む こんな感じです。 レイヤー0は4ビットカラーの0ビット目、 レイヤー1は4ビットカラーの1ビット目、 レイヤー2は4ビットカラーの2ビット目、 レイヤー3は4ビットカラーの3ビット目、 こうして組み立てられた4ビットカラーが座標(0,0)に表示されます。 座標(1,0)に色を表示させるには各レイヤーの6ビット目を0か1に任意で変化させます。 ここで気付いた方もいると思いますが、 「各レイヤー毎に同時に8ビットずつ変化させた方が速いのでは?」と思われたでしょう。 実はその通りです。 サンプルプログラムで1ピクセルしか描画していないのは レイヤー複数の画面の仕組みをシンプルに表現して理解しやすくするためです。 ここまでの説明で「プレーン」と表現すべき所を「レイヤー」と表現してきました。 「プレーンと表現してもピンと来ないのでは?」と思いましたし 「時代に合わせてレイヤーと表現した方が解りやすいのでは?」と思ったからです。 他のX68000の書籍ではレイヤーと言う表現はせずプレーンと表現しています。 今回はここまでで終わりです。 次回は任意の座標にピクセルを描画する方法を今回の続きとしてやります。 それでは、お疲れ様でした!! P.S. 気が付いた事があったらサンプルを書き換えて試したり サンプルにプログラムを追加して実験すると良いでしょう。 ------------------------------------------------------------------------------------------------ Comment from SEN::DAC君 写経、ご苦労様です〜☆ どう致しましてです!! > 約一年前、初めてX68000で画像を表示できたのがテキスト画面だったので思い入れがあります。 > https://dev.zuiki.com/project-z/community/post/detail/883 始めて画像を表示したターゲットがテキスト画面と言う辺りに個人的に才能を感じます(^^v 今回の1ピクセル表示は融通が利かないので、 次回は任意の座標に1ピクセルを描画する方法について説明する予定です。 > この先、画像を表示した後、テキストプレーンの同時アクセス機能も扱っていただけると、大変ありがたいです。。。! 実はテキストプレーン同時アクセス機能の存在は知っていたのですが使用した事がありません(^^; でも興味はあるので手持ちのX68000専門書全てで調べて勉強しマスターしたら公開します。 しばらくお待ちをm(__)m ------------------------------------------------------------------------------------------------ Comment from さかつきさん コメント頂き、有り難う御座います!! 参考にして頂けるとの事で喜んでいます(^^) 「dc.w $FE0D」の件ですが、「ランダム関数の初期化」の部分の削除し忘れです(^^; 第010回の時に$FE0Dと$FE0E(乱数を返す)を使用したサンプルプログラムを 今回のサンプルプログラムを作成する時にコピーして要らない部分を削除してから 今回のサンプルプログラムに必要な部分をコーディングして 動作チェックを入念に行っても全く誤動作しなかったので削除し忘れに気付けませんでした。 因みに「dc.w $FE0E * d0.lに0から32767のランダム値を返す」です。 なぜマクロを使わず「dc.w $FE0D」というふうにバイナリ配置しているのかというと 高校時代にX68000を買った後にマクロの入ったXCを買う余裕がなくて 「X68000環境ハンドブック」を頼りに$FE0Dと$FE0Eをバイナリ配置する癖が付いたからです(^^; > それと「スーパーバイザーモードからユーザーモードに戻る」でスタックから値を取り出していますが、 「move.l SP,a1」を「move.l -(SP),a1」と勘違いされていませんか? スーパーバイザーモードとユーザーモードの切り替えは アセンブラ開発キット福袋に付属のプログラマーズマニュアルの見本どおりに正確に行っています。 ------------------------------------------------------------------------------------------------ Comment from さかつきさん 高校生の頃にX68000を買うことができたのは 親が高校合格祝いでPC9801UV11とMS-DOSとアセンブラを買ってくれまして x86_16のアセンブラの勉強やゲームなどを楽しんで高2になった頃 ゲーム雑誌の中古店の広告で「X68000PRO \180000」と言うのを見付けて PC9801やゲーム機やゲームを全て中古店に売ったお金で間に合ったのでゲットできました(^^; $FExxのマクロファイルはアセンブラ開発キットに入ってなかったので X68000環境ハンドブックに描いてある数値をバイナリ配置するしか思い付きませんでした(^^; 環境ハンドブック、ある意味宝だと思っています。 問題が解決したようで何よりです(^^) アプリの始めに「IOCS _B_SUPER」でスーパーバイザーモードにして 終了時に「IOCS _B_SUPER」でユーザーモードにすれば あとはシステム領域をアクセスし放題なので便利です。 >  福袋はV1とV2がありますが、時期的にV1の方でしょうか。 > 付属のプログラマーズマニュアルはXCとは違うのですかね…。 V2を買って勉強しました。 V2のプログラマーズマニュアルの表紙に「C COMPILER PRO-68K」と書いてあります。 >  DOSコールとIOCSコールのマクロを使用されない理由は教えていただけないんですね。 すみません、書き忘れてました。 書籍を見ながら勉強していた時にマクロを使用しない書き方で覚えたので 今も癖として残っているだけです(^^; [EOF]